﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Forms;

namespace CameraWin
{
    public enum PointMoveType
    {
        Stop,
        Start,
        Move,
        Finish
    }
    public class Camera:ICamera
    {
        public int Index { get; set; } = 0;

        public int UserID { get; set; } = -1;

        public bool Recording { get; set; }
        public bool Speaking => SpeakHandle >= 0;
        public int RealHandle { get; set; } = -1;
        public int SpeakHandle { get; set; } = -1;
        private uint iLastErr = 0;
        private bool m_bInitSDK = false;
        private bool m_bTalk = false;
        private int lVoiceComHandle = -1;

        CHCNetSDK.REALDATACALLBACK RealData = null;
        CHCNetSDK.LOGINRESULTCALLBACK LoginCallBack = null;
        public CHCNetSDK.NET_DVR_PTZPOS m_struPtzCfg;
        public CHCNetSDK.NET_DVR_USER_LOGIN_INFO struLogInfo;
        public CHCNetSDK.NET_DVR_DEVICEINFO_V40 DeviceInfo;

        public CameraSet Set { get; set; }
        public IntPtr PanelPlay { get; set; }
        public bool Main { get; set; }
        public string Message { get; set; }
        public bool AudioState { get; set; }
        public List<int> Points { get; set; } = new List<int>();
        public int PointZero { get; set; }
        public uint PTZSpeed { get; set; } = 4;
        int pointIndex;
        DateTime pointTime;

        public event EventHandler<LogEventArgs> WriteLog;

        void OnWriteLog(string log)
        {
            if(WriteLog!=null)
            {
                WriteLog(this, new LogEventArgs() { LogText = log });
            }
        }
        public PointMoveType PointMove { get; set; }
        public Camera(int index, CameraSet set)
        {
            Index = index;
            Set = set;
        }
        public Camera(int index, IntPtr panel, CameraSet set) : this(index, set)
        {
            PanelPlay = panel;
        }

        public void Login()
        {
            if (UserID < 0 && Set != null && Set.Check())
            {
                struLogInfo = new CHCNetSDK.NET_DVR_USER_LOGIN_INFO();

                //设备IP地址或者域名
                byte[] byIP = Encoding.Default.GetBytes(Set.IP);
                struLogInfo.sDeviceAddress = new byte[129];
                byIP.CopyTo(struLogInfo.sDeviceAddress, 0);

                //设备用户名
                byte[] byUserName = Encoding.Default.GetBytes(Set.User);
                struLogInfo.sUserName = new byte[64];
                byUserName.CopyTo(struLogInfo.sUserName, 0);

                //设备密码
                byte[] byPassword = Encoding.Default.GetBytes(Set.Password);
                struLogInfo.sPassword = new byte[64];
                byPassword.CopyTo(struLogInfo.sPassword, 0);

                struLogInfo.wPort = (ushort)Set.Port;

                //if (LoginCallBack == null)
                //{
                //    LoginCallBack = new CHCNetSDK.LOGINRESULTCALLBACK(cbLoginCallBack);//注册回调函数
                //}

                struLogInfo.cbLoginResult = LoginCallBack;
                struLogInfo.bUseAsynLogin = false; //是否异步登录：0- 否，1- 是 

                DeviceInfo = new CHCNetSDK.NET_DVR_DEVICEINFO_V40();

                //登录设备 Login the device
                UserID = CHCNetSDK.NET_DVR_Login_V40(ref struLogInfo, ref DeviceInfo);
                if (UserID < 0)
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    Message = $"登录失败{iLastErr}";
                    OnWriteLog($"登录失败{iLastErr},{Set}");
                }
                else
                {
                    Message = $"登录成功{UserID};";
                    OnWriteLog($"登录成功{UserID},{Set}");
                }
                
            }
        }
        public void Logout()
        {
            CHCNetSDK.NET_DVR_Logout(UserID);
            UserID = -1;
        }
        public void RealPlay()
        {
            if (UserID < 0)
            {
                return;
            }

            if (RealHandle < 0 && PanelPlay != null)
            {
                CHCNetSDK.NET_DVR_PREVIEWINFO lpPreviewInfo = new CHCNetSDK.NET_DVR_PREVIEWINFO();
                lpPreviewInfo.hPlayWnd = PanelPlay;//预览窗口
                lpPreviewInfo.lChannel = Set.Channel;//预te览的设备通道
                lpPreviewInfo.dwStreamType = 0;//码流类型：0-主码流，1-子码流，2-码流3，3-码流4，以此类推
                lpPreviewInfo.dwLinkMode = 0;//连接方式：0- TCP方式，1- UDP方式，2- 多播方式，3- RTP方式，4-RTP/RTSP，5-RSTP/HTTP 
                lpPreviewInfo.bBlocked = false; //0- 非阻塞取流，1- 阻塞取流
                lpPreviewInfo.dwDisplayBufNum = 6; //播放库播放缓冲区最大缓冲帧数
                lpPreviewInfo.byProtoType = 0;
                lpPreviewInfo.byPreviewMode = 0;


                //if (RealData == null)
                //{
                //    RealData = new CHCNetSDK.REALDATACALLBACK(RealDataCallBack);//预览实时流回调函数
                //}

                IntPtr pUser = new IntPtr();//用户数据

                //打开预览 Start live view 
                RealHandle = CHCNetSDK.NET_DVR_RealPlay_V40(UserID, ref lpPreviewInfo, null/*RealData*/, pUser);
                if (RealHandle < 0)
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    Message += $"预览失败{iLastErr};";
                    OnWriteLog($"预览失败{iLastErr},{Set}");
                }
                else
                {
                    Message += $"预览成功{RealHandle};";
                    OnWriteLog($"预览成功{RealHandle},{Set}");
                }
            }
        }
        public void StopPlay()
        {
            if (UserID < 0)
            {
                return;
            }
            Message = "";
            StopAudio();
            StopSpeak();
            //停止预览 Stop live view 
            CHCNetSDK.NET_DVR_StopRealPlay(RealHandle);
            RealHandle = -1;
            RefreshWindow();
            OnWriteLog($"预览停止,{Set}");
        }
        public void RefreshWindow()
        {
            try
            {
                //panelPlay.Invalidate();//刷新窗口 refresh the window
            }
            catch
            {

            }
        }
        public void StartAudio()
        {

            if (UserID < 0 || RealHandle < 0)
            {
                return;
            }
            if (!Set.Audio || AudioState)
            {
                return;
            }
            if (CHCNetSDK.NET_DVR_SetAudioMode(2))
            {
                Message += $"共享音频;";
            }
            else
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                Message += $"共享音频错误{iLastErr};";
            }
            AudioState = CHCNetSDK.NET_DVR_OpenSoundShare(RealHandle);
            if (AudioState)
            {
                Message += $"播放声音成功;";
                if (CHCNetSDK.NET_DVR_Volume(RealHandle, 0xFFFF))
                {
                    Message += $"音量调节成功;";
                }
                else
                {
                    iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                    Message += $"音量调节失败{iLastErr};";
                }
            }
            else
            {
                iLastErr = CHCNetSDK.NET_DVR_GetLastError();
                Message += $"播放声音失败{iLastErr};";
            }
        }
        public void StopAudio()
        {
            if (UserID < 0 || RealHandle < 0)
            {
                return;
            }
            if (AudioState)
            {
                AudioState = false;
                CHCNetSDK.NET_DVR_CloseSoundShare(RealHandle);
            }
        }
        public void StartRecord(string folder)
        {
            if (UserID < 0)
            {
                return;
            }
            if (!Recording)
            {
                string path = Path.Combine(folder, $"{Index}_{DateTime.Now:yyyyMMddHHmmss}.mp4");
                //强制I帧 Make one key frame
                CHCNetSDK.NET_DVR_MakeKeyFrame(UserID, Set.Channel);
                //开始录像 Start recording
                Recording = CHCNetSDK.NET_DVR_SaveRealData(RealHandle, path);
            }
        }
        public void StopRecord()
        {
            if (UserID < 0)
            {
                return;
            }
            if (Recording)
            {
                if (CHCNetSDK.NET_DVR_StopSaveRealData(RealHandle))
                {
                    Recording = false;
                }
            }
        }

        public void StartSpeak()
        {
            if (UserID < 0)
            {
                return;
            }
            if (SpeakHandle<0)
            {
                SpeakHandle = CHCNetSDK.NET_DVR_StartVoiceCom(UserID,null, 0);
            }
        }
        public void StopSpeak()
        {
            if (UserID < 0)
            {
                return;
            }
            if (Speaking)
            {
                if (CHCNetSDK.NET_DVR_StopVoiceCom(SpeakHandle))
                {
                    SpeakHandle = -1;
                }
            }
        }
        public void PTZ(PTZType type)
        {
            if (UserID < 0 || RealHandle < 0)
            {
                return;
            }
            uint cmd = 0;
            uint stop = 0;
            switch(type)
            {
                case PTZType.Null:
                    stop = 1;
                    break;
                case PTZType.Up:
                    cmd = CHCNetSDK.TILT_UP;
                    break;
                case PTZType.Down:
                    cmd = CHCNetSDK.TILT_DOWN;
                    break;
                case PTZType.Left:
                    cmd = CHCNetSDK.PAN_LEFT;
                    break;
                case PTZType.Right:
                    cmd = CHCNetSDK.PAN_RIGHT;
                    break;
                case PTZType.ZoomIn:
                    cmd = CHCNetSDK.ZOOM_IN;
                    break;
                case PTZType.ZoomOut:
                    cmd = CHCNetSDK.ZOOM_OUT;
                    break;
                default:
                    stop = 1;
                    break;
            }
            //CHCNetSDK.NET_DVR_PTZControl(RealHandle, (uint)(zoomIn ? CHCNetSDK.ZOOM_OUT : CHCNetSDK.ZOOM_IN), (uint)(stop ? 1 : 0));
            CHCNetSDK.NET_DVR_PTZControlWithSpeed(RealHandle, cmd, stop, PTZSpeed);
        }

        public void Preset(uint point)
        {
            if (UserID < 0 || RealHandle < 0)
            {
                return;
            }
            if (point < 1 || point > 255)
            {
                return;
            }
            CHCNetSDK.NET_DVR_PTZPreset(RealHandle, CHCNetSDK.GOTO_PRESET, point);
        }
        public bool PresetAuto()
        {
            if (UserID < 0 || RealHandle < 0)
            {
                return false;
            }
            switch(PointMove)
            {
                case PointMoveType.Stop:
                    return false;
                case PointMoveType.Start:
                    pointIndex = 0;
                    pointTime = DateTime.Now;
                    Preset((uint)Points[pointIndex]);
                    PointMove = PointMoveType.Move;
                    break;
                case PointMoveType.Move:
                    if (DateTime.Now.Subtract(pointTime).TotalSeconds > 8)
                    {
                        pointIndex++;
                        pointTime = DateTime.Now;
                        if (pointIndex >= Points.Count)
                        {
                            pointIndex = 0;
                            
                        }
                        Preset((uint)Points[pointIndex]);
                        //else
                        //{
                        //    Preset((uint)PointZero);
                        //    PointMove = PointMoveType.Finish;
                        //}
                    }
                    break;
                case PointMoveType.Finish:
                    if (DateTime.Now.Subtract(pointTime).TotalSeconds > 2)
                    {
                        PointMove = PointMoveType.Stop;
                    }
                    break;
            }
            return true;
        }
        public void PresetReset()
        {
            Preset((uint)PointZero);
            pointTime = DateTime.Now;
            PointMove = PointMoveType.Stop;
        }

        
    }
}
